﻿using CommonLibraries.DeviceLibrary;
using CommonLibraries.DeviceLibrary.Helpers;
using PolePositionMobile.Data;
using PolePositionMobile.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlServerCe;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using PolePositionMobileClasses.Exception;

namespace PolePositionMobile
{
    /// <summary>
    /// Base form which all the others inherit.
    /// </summary>
    public partial class frmBase : System.Windows.Forms.Form
    {
        //Created by: VMCoder
        //Creation date: -
        //Last updated by: VMCoder
        //Last update: 2008.04.15

        #region External Methods
        /// <summary>
        /// Returns total number of bytes, number of free bytes and free bytes available for a given path.
        /// </summary>
        [DllImport("coredll")]
        public static extern int GetDiskFreeSpaceEx(string lpDirectoryName, ref long lpFreeBytesAvailable, ref long lpTotalNumberOfBytes, ref long lpTotalNumberOfFreeBytes);
        #endregion
        #region Private and Protected Members
        //To be used in conjunction with the corresponding properties to control menu offset
        private Int32 m_LButtonMenuXOffset = 0;
        private Int32 m_LButtonMenuYOffset = 0;
        private Int32 m_RButtonMenuXOffset = 0;
        private Int32 m_RButtonMenuYOffset = 0;
        protected long m_TotalNumberOfBytes = 0;
        protected long m_TotalNumberOfFreeBytes = 0;
        protected GPS m_GPS = GPS.GetInstance();
        protected Handheld m_Handheld = Handheld.GetInstance();
        protected Int32 m_NoSignalCounter = 5;
        protected ESettingsStructure m_Settings;
        //WARNING: These values were calculated by observing and comparing 'Remaining Power' in the Power
        //dialog in the Control Panel and the results retrieved from m_Handheld.BatteryLevel. For that reason
        //they should be considered as approximate values.
        const int m_MinBatteryLevel = 6500;
        const int m_MaxBatteryLevel = 8230;
        #endregion
        #region Public Properties
        public Int32 LButtonMenuXOffset
        {
            get { return m_LButtonMenuXOffset; }
            set { m_LButtonMenuXOffset = value; }
        }
        public Int32 LButtonMenuYOffset
        {
            get { return m_LButtonMenuYOffset; }
            set { m_LButtonMenuYOffset = value; }
        }
        public Int32 RButtonMenuXOffset
        {
            get { return m_RButtonMenuXOffset; }
            set { m_RButtonMenuXOffset = value; }
        }
        public Int32 RButtonMenuYOffset
        {
            get { return m_RButtonMenuYOffset; }
            set { m_RButtonMenuYOffset = value; }
        }
        public Int32 PolesNumber
        {
            set
            {
                if (value > 0)
                    tabPoles.Text = "Poles (" + value.ToString() + ")";
                else
                    tabPoles.Text = "Poles";
            }
        }
        public Int32 PhotosNumber
        {
            set
            {
                if (value > 0)
                    tabPhotos.Text = "Photos (" + value.ToString() + ")";
                else
                    tabPhotos.Text = "Photos";
            }
        }
        public ESettingsStructure Settings
        {
            set
            {
                m_Settings = value;
            }
            get
            {
                return m_Settings;
            }
        }
        public int SolutionStatus
        {
            set
            {
                lblSolutionStatus.BackColor = SetStatus(value);
                lblSolutionStatus.Tag = value;
                lblSolutionStatus.Update();
                Application.DoEvents();
            }
        }
        public int DiskStatus
        {
            set
            {
                lblDiskStatus.BackColor = SetStatus(value);
                lblDiskStatus.Tag = value;
                lblDiskStatus.Update();
                Application.DoEvents();
            }
        }
        public int BatteryStatus
        {
            set
            {
                lblBatteryStatus.BackColor = SetStatus(value);
                lblBatteryStatus.Tag = value;
                lblBatteryStatus.Update();
                Application.DoEvents();
            }
        }
        #endregion

        public frmBase()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Handler for Form Load event
        /// </summary>
        private void frmBase_Load(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.15

            SetCorrectOrder();

            //Temporary. For emulator only.
            //this.Top -= 27;

            ComponentResourceManager resources = new ComponentResourceManager(typeof(frmBase));

            //If the dll is not in the Windows folder, copy it from the resources
            if (!File.Exists(PPIConstants.K_DllPath))
            {
                if (!Directory.Exists(PPIConstants.K_WindowsFolder))
                    Directory.CreateDirectory(PPIConstants.K_WindowsFolder);
                byte[] _SourceFile = (byte[])resources.GetObject("TGMS2HELPER");
                if (_SourceFile != null)
                {
                    FileStream _DllFile = File.Create(PPIConstants.K_DllPath);
                    _DllFile.Write(_SourceFile, 0, (int)(_SourceFile.Length));
                    _DllFile.Flush();
                    _DllFile.Close();
                    _DllFile.Dispose();
                }
                else
                    throw new Exception(Constants.K_MissingTGMS2HELPER);
            }

            //If the images folder doesn't exist, create it
            if (!Directory.Exists(PPIConstants.K_ImagesFolder))
                Directory.CreateDirectory(PPIConstants.K_ImagesFolder);

            //If there is no database, copy an empty one from the resources
            if (!File.Exists(PPIConstants.K_DBPath))
            {
                throw new ExceptionNotFoundDatabase("Database not found. Please verify PolePositionMobile.sdf is located at " + PPIConstants.K_DBPath);
            }

            //Retrieves settings form the database if they aren't defined
            if (m_Settings == null)
                m_Settings = Logic.LogicLayer.GetSettings();

            if (String.IsNullOrEmpty(m_Settings.VersionDatabase))
                throw new ExceptionIncorrectVersion("Incorrect database version. Please verify PolePositionMobile.sdf located at " + PPIConstants.K_DBPath);
            

            GPSOn();

            m_GPS.HasSolutionChanged += new EventHandler(m_GPS_HasSolutionChanged);

            //Starts solution status
            SolutionStatus = m_GPS.HasSolution ? (Int32)SquareColors.Green : (Int32)SquareColors.Red;

            //Starts disk status
            CheckDisk();

            //Starts battery status
            CheckBattery();
        }

        /// <summary>
        /// Set correct Z-Order
        /// </summary>
        protected void SetCorrectOrder()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            pbxHeader.SendToBack();
            lblLButtonText.BringToFront();
            lblRButtonText.BringToFront();
            lblLButton.BringToFront();
            lblRButton.BringToFront();
            lblBatteryStatus.BringToFront();
            lblDiskStatus.BringToFront();
            lblSolutionStatus.BringToFront();
        }

        /// <summary>
        /// Handler for lblLButton Click event
        /// </summary>
        protected virtual void lblLButton_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If this button has a context menu, display it
            if (lblLButton.ContextMenu != null)
                lblLButton.ContextMenu.Show(this, new Point(lblLButton.Left + m_LButtonMenuXOffset, lblLButton.Top - m_LButtonMenuYOffset));
        }
        /// <summary>
        /// Handler for lblRButton Click event
        /// </summary>
        protected virtual void lblRButton_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If this button has a context menu, display it
            if (lblRButton.ContextMenu != null)
                lblRButton.ContextMenu.Show(this, new Point(lblRButton.Left + m_RButtonMenuXOffset, lblRButton.Top - m_RButtonMenuYOffset));
        }
        /// <summary>
        /// Handler for lblLButtonText Click event
        /// </summary>
        private void lblLButtonText_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If button text is clicked, redirect to handler of main button
            lblLButton_Click(sender, e);
        }
        /// <summary>
        /// Handler for lblRButtonText Click event
        /// </summary>
        private void lblRButtonText_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If button text is clicked, redirect to handler of main button
            lblRButton_Click(sender, e);
        }
        /// <summary>
        /// Handler for lblClose Click event
        /// </summary>
        protected virtual void lblClose_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Delete temp images and exit the application
            DeleteTempFiles();
            if (MessageBox.Show("Are you sure you want to exit?", PPIConstants.K_AppName, MessageBoxButtons.YesNo, MessageBoxIcon.None, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                Application.Exit();
        }

        #region StatusFunctions
        /// <summary>
        /// Returns corresponding status color (if applicable)
        /// </summary>
        protected Color SetStatus(int status)
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            Color res = Color.Indigo;
            switch (status)
            {
                case 3:
                    res = Color.White;
                    break;
                case 2:
                    res = Color.Yellow;
                    break;
                case 1:
                    res = Color.Lime;
                    break;
                case 0:
                    res = Color.Red;
                    break;
            }
            return res;
        }
        #endregion

        #region GPS
        /// <summary>
        /// Powers GPS on
        /// </summary>
        protected void GPSOn()
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: GBarzola
            //Last update: -

            if (m_GPS.PowerState == PowerStates.Off)
            {
                m_GPS.Reset();
                m_GPS.PowerState = PowerStates.On;
            }
        }
        private delegate void ThreadDelegate();
        /// <summary>
        /// Handler for m_GPS HasSolutionChanged event
        /// </summary>
        public void m_GPS_HasSolutionChanged(object sender, EventArgs e)
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: GBarzola
            //Last update: -

            try
            {
                //Invoke HasSolutionChanged in a new thread
                this.Invoke(new ThreadDelegate(this.HasSolutionChanged));
            }
            catch (ObjectDisposedException ex)
            {
                ErrorManager.CreateDebug("BeginInvoke->" + ex.Message);
            }
        }
        /// <summary>
        /// Changes display depending on GPS solution status.
        /// </summary>
        protected void HasSolutionChanged()
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Changes display depending on GPS solution status. To avoid Blinking, solution detection must
            //fail at least 5 times in a row to display a red icon.
            try
            {
                if (!m_GPS.HasSolution)
                {
                    if (m_NoSignalCounter == 0)
                    {
                        SolutionStatus = (int)SquareColors.Red;
                    }
                    else
                        m_NoSignalCounter--;
                }
                else
                {
                    SolutionStatus = (int)SquareColors.Green;
                    m_NoSignalCounter = 5;
                }
                GPSOn();
                CheckDisk();
                CheckBattery();
            }
            catch (Exception ex)
            {
                ErrorManager.CreateDebug("HasSolutionChanged->Problems\n" + ex.Message);
            }
        }
        #endregion
        #region Storage
        /// <summary>
        /// Calculates disk space status from total storage space and free space.
        /// 100% - 51% = Good
        /// 50% - 21% = Low
        /// 20% - 1% = Very Low
        /// </summary>
        private void CheckDisk()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            long _FreeBytesAvailable = 0;
            long _TotalNumberOfBytes = 0;
            long _TotalNumberOfFreeBytes = 0;

            GetDiskFreeSpaceEx(PPIConstants.K_SDCardPath, ref _FreeBytesAvailable, ref _TotalNumberOfBytes, ref _TotalNumberOfFreeBytes);

            int _CurrentPercentage = Convert.ToInt32(_TotalNumberOfFreeBytes * 100 / _TotalNumberOfBytes);

            if (_CurrentPercentage >= 51 && _CurrentPercentage <= 100)
                DiskStatus = (int)SquareColors.Green;
            else if (_CurrentPercentage < 51 && _CurrentPercentage > 20)
                DiskStatus = (int)SquareColors.Yellow;
            else
                DiskStatus = (int)SquareColors.Red;

            m_TotalNumberOfBytes = _TotalNumberOfBytes;
            m_TotalNumberOfFreeBytes = _TotalNumberOfFreeBytes;
        }
        #endregion
        #region Battery
        /// <summary>
        /// Returns an approximation of current battery level (almost always the same value as in the Power
        /// dialog in the Control Panel)
        /// </summary>
        protected double GetEnergyPercentage(Int32 batteryLevel)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            return Convert.ToDouble((batteryLevel - m_MinBatteryLevel) * 100) / (m_MaxBatteryLevel - m_MinBatteryLevel);
        }
        /// <summary>
        /// Calculates battery level.
        /// 100% - 51% = Good
        /// 50% - 26% = Low
        /// 25% - 1% = Very Low
        /// </summary>
        private void CheckBatteryLevel()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            int _CurrentLoadPercentage = Convert.ToInt32(GetEnergyPercentage(m_Handheld.BatteryLevel));

            if (_CurrentLoadPercentage >= 51 && _CurrentLoadPercentage <= 100)
                BatteryStatus = (int)SquareColors.Green;
            else if (_CurrentLoadPercentage < 51 && _CurrentLoadPercentage > 25)
                BatteryStatus = (int)SquareColors.Yellow;
            else
                BatteryStatus = (int)SquareColors.Red;
        }
        /// <summary>
        /// Returns White if connected to the power cord, or the corresponding status if not.
        /// </summary>
        private void CheckBattery()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            if (m_Handheld.PowerSource == PowerSources.Battery)
                CheckBatteryLevel();
            else
                BatteryStatus = (int)SquareColors.White;
        }
        #endregion


        /// <summary>
        /// Handler for tabMain Click event
        /// </summary>
        protected virtual void tabMain_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //To be overridden in children forms
        }
        /// <summary>
        /// Handler for tabPoles Click event
        /// </summary>
        protected virtual void tabPoles_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //To be overridden in children forms
        }
        /// <summary>
        /// Handler for tabPhotos Click event
        /// </summary>
        protected virtual void tabPhotos_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //To be overridden in children forms
        }

        /// <summary>
        /// Handler for tbcTabs SelectedIndexChanged event
        /// </summary>
        private void tbcTabs_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Since the individual tabs' events don't work properly, we're forced to call them from here
            switch (tbcTabs.SelectedIndex)
            {
                case 0:
                    tabMain_Click(sender, e);
                    break;
                case 1:
                    tabPoles_Click(sender, e);
                    break;
                case 2:
                    tabPhotos_Click(sender, e);
                    break;
            }
        }

        /// <summary>
        /// Shows a 'Loading' screen
        /// </summary>
        protected void ShowLoading()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            lblTitle.Text = "Loading...";
            lblLoading.Visible = true;
            lblLoading.BringToFront();
            pbxHourglass.Visible = true;
            pbxHourglass.BringToFront();
        }
        /// <summary>
        /// Hides the 'Loading' screen (replacing the title)
        /// </summary>
        protected void HideLoading(string title)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            lblTitle.Text = title;
            lblLoading.Visible = false;
            pbxHourglass.Visible = false;
            SetCorrectOrder();
        }

        /// <summary>
        /// Handler for lblBatteryStatus Click event
        /// </summary>
        private void lblBatteryStatus_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Displays battery status details
            switch ((Int32)lblBatteryStatus.Tag)
            {
                case (Int32)SquareColors.White:
                    MessageBox.Show("Handheld is connected to Power Plug (" + GetEnergyPercentage(m_Handheld.BatteryLevel).ToString("F0") + "%)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Green:
                    MessageBox.Show("Current Battery Level is Good (" + GetEnergyPercentage(m_Handheld.BatteryLevel).ToString("F0") + "%)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Yellow:
                    MessageBox.Show("Current Battery Level is Low (" + GetEnergyPercentage(m_Handheld.BatteryLevel).ToString("F0") + "%)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Red:
                    MessageBox.Show("Current Battery Level is Very Low (" + GetEnergyPercentage(m_Handheld.BatteryLevel).ToString("F0") + "%)", PPIConstants.K_AppName);
                    break;
                default:
                    MessageBox.Show("Current Battery Level is unknown", PPIConstants.K_AppName);
                    break;
            }
        }
        /// <summary>
        /// Handler for lblDiskStatus Click event
        /// </summary>
        private void lblDiskStatus_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Displays disk status details
            switch ((Int32)lblDiskStatus.Tag)
            {
                case (Int32)SquareColors.Green:
                    MessageBox.Show("Current Storage Level is Good (" + Convert.ToInt32(m_TotalNumberOfFreeBytes * 100 / m_TotalNumberOfBytes).ToString() + "%)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Yellow:
                    MessageBox.Show("Current Storage Level is Low (" + Convert.ToInt32(m_TotalNumberOfFreeBytes * 100 / m_TotalNumberOfBytes).ToString() + "%)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Red:
                    MessageBox.Show("Current Storage Level is Very Low (" + Convert.ToInt32(m_TotalNumberOfFreeBytes * 100 / m_TotalNumberOfBytes).ToString() + "%)", PPIConstants.K_AppName);
                    break;
                default:
                    MessageBox.Show("Current Storage Level is unknown", PPIConstants.K_AppName);
                    break;
            }
        }
        /// <summary>
        /// Handler for lblSolutionStatus Click event
        /// </summary>
        private void lblSolutionStatus_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Displays solution status details
            switch ((Int32)lblSolutionStatus.Tag)
            {
                case (Int32)SquareColors.Green:
                    MessageBox.Show("GPS Solution is currently available - " + m_GPS.NmeaGGA.SateliteCount + " satellite(s)", PPIConstants.K_AppName);
                    break;
                case (Int32)SquareColors.Red:
                    MessageBox.Show("GPS Solution is currently unavailable", PPIConstants.K_AppName);
                    break;
                default:
                    MessageBox.Show("GPS Solution status is unknown", PPIConstants.K_AppName);
                    break;
            }
        }

        /// <summary>
        /// Deletes temporary files (i.e., photos taken in a cancelled visit)
        /// </summary>
        protected void DeleteTempFiles()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            foreach (string _File in Directory.GetFiles(PPIConstants.K_ImagesFolder))
                if (_File.IndexOf("temp") > -1)
                    File.Delete(_File);
        }

        /// <summary>
        /// Sets the solution values for all the poles and images of a visit
        /// </summary>
        protected void SetInnerSolutions(EVisit visit)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            if (visit != null)
            {
                if (visit.Data != null && visit.Data.Poles != null)
                {
                    foreach (EPole _Pole in visit.Data.Poles)
                    {
                        _Pole.Longitude = visit.Longitude;
                        _Pole.Latitude = visit.Latitude;
                        _Pole.Altitude = visit.Altitude;
                        _Pole.SatelliteCount = visit.SatelliteCount;
                        _Pole.SatelliteTime = visit.SatelliteTime;
                        _Pole.SolutionAvailable = visit.SolutionAvailable;
                    }
                }
                if (visit.Images != null)
                {
                    foreach (EImage _Image in visit.Images)
                    {
                        _Image.Longitude = visit.Longitude;
                        _Image.Latitude = visit.Latitude;
                        _Image.Altitude = visit.Altitude;
                        _Image.SatelliteCount = visit.SatelliteCount;
                        _Image.SatelliteTime = visit.SatelliteTime;
                        _Image.SolutionAvailable = visit.SolutionAvailable;
                    }
                }
            }
        }
        /// <summary>
        /// Resets a visits solution
        /// </summary>
        protected void ResetSolution(EVisit visit)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            if (!m_GPS.HasSolution)
            {
                frmManuallyEnterPosition _Form = new frmManuallyEnterPosition();
                _Form.Visit = visit;
                _Form.Settings = this.Settings;
                _Form.Show();
                this.Hide();
            }
            else
            {
                string stemp = "";
                frmDataCollectionStructure _Form = new frmDataCollectionStructure();
                _Form.Visit = visit;
                _Form.Visit.Longitude = Utils.ConvertLongitudeToDecimal(m_GPS.NmeaGGA.Longitude, m_GPS.NmeaGGA.LongitudeHemisphere, ref stemp);
                _Form.Visit.Latitude = Utils.ConvertLatitudeToDecimal(m_GPS.NmeaGGA.Latitude, m_GPS.NmeaGGA.LatitudeHemisphere, ref stemp);
                _Form.Visit.Altitude = double.Parse(m_GPS.NmeaGGA.Altitude.ToString());
                _Form.Visit.SatelliteCount = m_GPS.NmeaGGA.SateliteCount;
                _Form.Visit.SatelliteTime = m_GPS.NmeaGGA.SateliteTime;
                _Form.Visit.SolutionAvailable = true;
                SetInnerSolutions(_Form.Visit);
                _Form.Settings = this.Settings;
                _Form.Show();
                this.Hide();
            }
        }
    }
}
